﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.IO;

namespace BMproductions.Media.MediaPlayer.WMPPlus {
	public enum PluginRestoreOption { opt0, opt1, opt2 }
	public struct PluginRestoreSettings {
		public bool Enabled;
		public PluginRestoreOption Option;
		public bool NoDialog;
	}

	public class PluginRestore: IDisposable, IPluginManager {
		WMPPlusHookData hook;
		PluginManager plugins;
		RegistryKey registry;

		private enum PersistAction { Load, Save }

		[return: MarshalAs(UnmanagedType.Bool)]
		[DllImport(WMPPlusPublic.WMPPlusHookName, EntryPoint = "#401")]
		public static extern bool CheckError(IntPtr hWnd);

		#region IPluginManager implementation
		void IPluginManager.Register(WMPPlugin plugin) {}
		void IPluginManager.Unregister(WMPPlugin plugin) {}
		#endregion

		public PluginRestore(WMPPlusHookData hook, PluginManager plugins) {
			this.hook = hook;
			this.plugins = plugins;
			var root = Registry.CurrentUser;
			this.registry = root.CreateSubKey(Path.Combine(WMPPlusCore.WMPPlusRegKey, "RunningPlugins"));
			GetRunningPlugins();
			this.plugins.AddModule(this as IPluginManager);
		}

		public void Dispose() {
			this.plugins.RemoveModule(this as IPluginManager);
			this.registry.Close();
		}

		private void PersistRegistry(RegistryKey key, string name, ref int value, int defValue, PersistAction action) {
			switch (action) {
			case PersistAction.Save:
				WMPPlusSettings.SaveRegistryNumber(key, name, value);
				break;
			case PersistAction.Load:
				value = WMPPlusSettings.LoadRegistryNumber(key, name, defValue);
				break;
			}
		}

		private void PersistRegistry(RegistryKey key, string name, ref bool value, bool defValue, PersistAction action) {
			switch (action) {
			case PersistAction.Save:
				key.SetValue(name, value ? 1 : 0, RegistryValueKind.DWord);
				break;
			case PersistAction.Load:
				value = WMPPlusSettings.LoadRegistryBool(key, name, defValue);
				break;
			}
		}

		private void PersistPluginRestore(ref PluginRestoreSettings settings, PersistAction action) {
			if (action == PersistAction.Load) {
				settings.Enabled = true;
				settings.Option = PluginRestoreOption.opt0;
				settings.NoDialog = false;
			}
			var root = Registry.CurrentUser;
			using (var key = action == PersistAction.Save ?
				root.CreateSubKey(WMPPlusCore.WMPPlusRegKey) :
				root.OpenSubKey(WMPPlusCore.WMPPlusRegKey, false)) {
				if (key == null) return;
				PersistRegistry(key, "PluginRestoreEnabled", ref settings.Enabled, true, action);
				int n1 = 0;
				if (action != PersistAction.Load)
					n1 = (int)settings.Option;
				PersistRegistry(key, "PluginRestoreOption", ref n1, 0, action);
				if (action == PersistAction.Load) {
					settings.Option = (PluginRestoreOption)(n1 > 2 ? 0 : n1);
				}
				PersistRegistry(key, "PluginRestoreNoDialog", ref settings.NoDialog, false, action);
			}
		}

		public PluginRestoreSettings LoadSettings() {
			PluginRestoreSettings settings = new PluginRestoreSettings();
			PersistPluginRestore(ref settings, PersistAction.Load);
			return settings;
		}

		public void SaveSettings(PluginRestoreSettings settings) {
			PersistPluginRestore(ref settings, PersistAction.Save);
		}

		public void LoadPlugin(WMPPlugin plugin) {
			WMPPlusSettings.SaveRegistryString(this.registry, null, plugin.CLSID.ToString("B"));
		}

		public void UnloadPlugin(WMPPlugin plugin) {
			if (!hook.WMPlayerClosing) {
				this.registry.DeleteSubKey(plugin.CLSID.ToString("B"));
			}
		}

		int GetRunningPlugins(ICollection<Guid> list, bool clear, bool validate) {
			int count = 0;
			var keys = this.registry.GetSubKeyNames();
			if (clear)
				foreach (string key in keys)
					this.registry.DeleteSubKey(key);
			foreach (string key in keys) {
				Guid clsid = Guid.Empty;
				bool failed;
				try {
					clsid = new Guid(key);
					failed = false;
				} catch {
					failed = true;
				}
				if (validate) {
					failed = failed || plugins.Find(clsid, false) == null;
					if (failed)
						this.registry.DeleteSubKey(key);
				}
				if (!failed) {
					count++;
					if (list != null)
						list.Add(clsid);
				}
			}
			return count;
		}

		void SetPluginRunning(WMPPlugin plugin) {
			var root = Registry.CurrentUser;
			using (var key = root.OpenSubKey(plugin.KeyPath)) {
				WMPPlusSettings.SaveRegistryNumber(key, "Running", 1);
			}
		}

		bool sub_518D00() {
			var settings = LoadSettings();
			if (!settings.Enabled)
				return false;
			return GetRunningPlugins(null, false, false) != 0;
		}

		int GetRunningPlugins() {
			return GetRunningPlugins(null, false, true);
		}
	}
}
